package com.zeddy.android.HarrisVoice;

/*
 * @Filename: 	HarrisTcpTransport.java
 * @Classname: 	HarrisTcpTransport
 * @Author:		i.z.chirombe@wustl.edu
 * 
 * @Description:	This class is just a library class, whose purpose is to facilitates
 * 				Network programming over USB Interface. Based on the way Android Development 
 * 				Bridge(adb) works, this interface only support running in server mode
 * 				only. 
 * 
 * 				The PC based clients, assumes your devices are already connected via
 * 				USB, and that adb bridge is fully functional. If any problem, you not know
 * 				from this side, but rather check the PC client's connection dialog, and 
 * 				correct problem if any. But rule of thump, just make sure the android 
 * 				bridge is usable, and don't forget reactivate port forwarding. 
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

import android.os.Handler;
import android.util.Log;
import android.widget.TextView;

/**
 * @author zeddy.chirombe
 *
 */
public class HarrisTcpTransport {
	public enum TcpErrors { SUCCESS, INACTIVE, ACCEPT_FAILED, IOEXCEPTION,
		SECURITY_EXCEPTION, SETUP_EXCEPTION, ZERO_BYTE_READ, UNDEFINED_TRANS};
	private static boolean DEBUG = true;
	private static final String TAG = "HarrisTcpTransport";
	private ServerSocket tcpServer = null;
	private Socket mySocket = null;
	private BufferedReader ioInput = null;
	private PrintWriter ioOutput = null;

	private Handler activityHandler = null;
	private boolean activeTransport = false;
	
	private TextView logView = null;

	/**
	 * Constructor - 
	 */
	public HarrisTcpTransport(Handler _handler, TextView _logView) {
		activityHandler = _handler;
		logView = _logView;

	}
	
	public void showPost(final String msg) {
		if(DEBUG) { Log.e(TAG,msg);}
		activityHandler.post(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				logView.setText(msg+System.getProperty("line.separator")+logView.getText());
			}	
		});
	}
 
    /** Will cancel the listening socket, and cause the thread to finish */
    public void cancel() {
        try {
        	tcpServer.close();
        } catch (IOException e) { }
    }
	 
	//-------------------------------------------------------------------
	   
	/*
	 * AndroidTransport starts here -------
	*/
	public TcpErrors transSetup() {
		// set up Server TCP connection - 
		activeTransport = false;
		try {
			tcpServer = new ServerSocket(7500);
			int prt = tcpServer.getLocalPort(); 
			String ipAddr = tcpServer.getInetAddress().getHostAddress();
			//Log.e(TAG,"ATR:: +Open Port: "+prt+"\n Ip-Addr: "+ipAddr);
			showPost("ATR:: +Open Port: "+prt+"\n Ip-Addr: "+ipAddr);
			return listen();
		} catch (SecurityException ex) {
			showPost("ATR:: "+ex);	
			activeTransport = false;
			return TcpErrors.SECURITY_EXCEPTION;
		} catch (IOException ex) {
			showPost("ATR:: "+ex);
			activeTransport = false;
		}
		return TcpErrors.IOEXCEPTION;
	}
	
	public TcpErrors listen() {
		showPost("Android Transport - OK");
		showPost("Listening for client connection....");
		try {
			mySocket = tcpServer.accept();
			if((mySocket == null) || !mySocket.isConnected()) {
				showPost("TCP-Accept() Failed.");
				return TcpErrors.ACCEPT_FAILED;
			}
			if(ioInput!= null) ioInput = null;
			if(ioOutput!= null) ioOutput = null;		
			ioInput=new BufferedReader(new InputStreamReader(mySocket.getInputStream()));
			ioOutput = new PrintWriter(mySocket.getOutputStream(), false);
			String intro = "ANDROID_INTRO:android:Connected - Welcome aboard.";
			//set send welcom message - 
			ioOutput.write(intro);
			ioOutput.flush();
			activeTransport = true;
			return TcpErrors.SUCCESS;	
		} catch (IOException ex) {
			activeTransport = false;
		}
		return TcpErrors.IOEXCEPTION;
	}
	
	public TcpErrors recv_msg(HarrisMessage hMsg) {
		// Keep listening until exception or socket - 
		if(!activeTransport) {
			showPost("Transport inactive...exiting");
			return TcpErrors.INACTIVE;
		}
		try {
			showPost("...awaiting-new-msg...");
			if((mySocket != null) && (mySocket.isConnected())) {
				hMsg.reset();
				String msg = ioInput.readLine();
				if(msg.equals("null")) {
					//showPost("dbg - zerobyte");
					return TcpErrors.ZERO_BYTE_READ;
				}
				if(hMsg.parse_list(msg)) {
					//showPost("dgb - success");
					return TcpErrors.SUCCESS;
				}
				showPost("Malformed Msg[ "+msg+" ] ");
			}
		} catch (IOException e) {
			showPost("Error-reading TCP-socket ...\n");
			activeTransport = false;
			mySocket = null;
    	} catch (Exception e) {
			showPost("Error-reading TCP-socket ...\n");
			activeTransport = false;
			mySocket = null;
    	}
		return TcpErrors.IOEXCEPTION;
	}
	public void post_msg(final String reply) {
		activityHandler.post(new Runnable() {
			@Override
			public void run() {
				if((mySocket != null) && (mySocket.isConnected())) {
					try {
						ioOutput.write(reply+"\n");
						ioOutput.flush();
						//pw.write("+Yes, I can help, but you will have to pay.\n");
					} catch (NullPointerException e) {
						showPost("postReply() "+e);
						activeTransport = false;
					} catch (Exception e) {
						showPost("postReply() "+e);
						activeTransport = false;
					}
				}
				showPost("....trans-stop....");
			}	
		});	
	}
	public void send_msg(final String reply) {
		if((mySocket != null) && (mySocket.isConnected())) {
			try {
				ioOutput.write(reply+"\n");
				ioOutput.flush();
				//pw.write("+Yes, I can help, but you will have to pay.\n");
			} catch (NullPointerException e) {
				showPost("postReply() "+e);
				activeTransport = false;
			} catch (Exception e) {
				showPost("postReply() "+e);
				activeTransport = false;
			}
		}
		showPost("....trans-stop....");
	}
}
